//
//  TransitionsView.swift
//  animations
//
//  Created by Ekaterina on 18.01.2023.
//

import SwiftUI

struct TransitionsView: View {
    @State var isViewShown = false
    
    @State var isAsymmetric = false
    @State var firstInsertionIndex = 0
    @State var secondInsertionIndex = -1
    @State var firstRemovalIndex = 0
    @State var secondRemovalIndex = -1
    
    @State var animationIndex = 0
    
    @State var duration = 1.0
    
    let minDuration = 0.2
    let maxDuration = 2.0
    
    let transitions = [
        TransitionItem(title: "Slide", value: AnyTransition.slide),
        TransitionItem(title: "Scale", value: AnyTransition.scale),
        TransitionItem(title: "Opacity", value: AnyTransition.opacity),
        TransitionItem(title: "Move Top", value: AnyTransition.move(edge: .top)),
        TransitionItem(title: "Move Bottom", value: AnyTransition.move(edge: .bottom)),
        TransitionItem(title: "Move Leading", value: AnyTransition.move(edge: .leading)),
        TransitionItem(title: "Move Trailing", value: AnyTransition.move(edge: .trailing)),
        TransitionItem(title: "Offset (100)", value: AnyTransition.offset(x: 100, y: 100)),
        TransitionItem(title: "Offset (300)", value: AnyTransition.offset(x: 300, y: 300)),
        TransitionItem(title: "Offset (-100)", value: AnyTransition.offset(x: -100, y: -100)),
        TransitionItem(title: "Offset (-300)", value: AnyTransition.offset(x: -300, y: -300))
    ]
    
    let animations = [
        AnimationItem(title: "Linear", value: Animation.linear(duration: 1)),
        AnimationItem(title: "Ease In", value: Animation.easeIn(duration: 1)),
        AnimationItem(title: "Ease Out", value: Animation.easeOut(duration: 1)),
        AnimationItem(title: "Ease In Out", value: Animation.easeInOut(duration: 1)),
        AnimationItem(title: "Spring", value: Animation.spring(response: 0.5, dampingFraction: 0.5, blendDuration: 1)),
        AnimationItem(title: "Interactive Spring", value: Animation.interactiveSpring(response: 0.5, dampingFraction: 0.5, blendDuration: 1)),
        AnimationItem(title: "Interpolating Spring", value: Animation.interpolatingSpring(stiffness: 1, damping: 0.8))
    ]
    
    var body: some View {
        ZStack {
            VStack(spacing: 24) {
                VStack(spacing: 8) {
                    VStack(spacing: 0) {
                        Text("Animation type").font(.system(size: 16, weight: .bold))
                        Picker("", selection: $animationIndex) {
                            ForEach(0...animations.count - 1, id: \.self) { index in
                                Text(animations[index].title).font(.system(size: 16))
                            }
                        }
                        .pickerStyle(.wheel)
                        .frame(maxHeight: 120)
                    }
                    
                    Divider()
                    
                    VStack(spacing: 0) {
                        Text("Insertion Transition").font(.system(size: 16, weight: .bold))
                        HStack {
                            Picker("", selection: $firstInsertionIndex) {
                                ForEach(0...transitions.count - 1, id: \.self) { index in
                                    getTransitionText(index: index)
                                }
                            }
                            .pickerStyle(.wheel)
                            .frame(maxHeight: 120)
                            
                            Spacer()
                            
                            Picker("", selection: $secondInsertionIndex) {
                                ForEach(-1...transitions.count - 1, id: \.self) { index in
                                    getTransitionText(index: index)
                                }
                            }
                            .pickerStyle(.wheel)
                            .frame(maxHeight: 120)
                        }
                    }
                    
                    Divider()
                    
                    Toggle(isOn: $isAsymmetric) {
                        Text("Asymmetric Transition")
                    }
                    .toggleStyle(.switch)
                    .tint(.accentColor)
                    
                    VStack(spacing: 0) {
                        Text("Removal Transition").font(.system(size: 16, weight: .bold))
                        HStack {
                            Picker("", selection: $firstRemovalIndex) {
                                ForEach(0...transitions.count - 1, id: \.self) { index in
                                    getTransitionText(index: index)
                                }
                            }
                            .pickerStyle(.wheel)
                            .frame(maxHeight: 120)
                            .disabled(!isAsymmetric)
                            
                            Spacer()
                            
                            Picker("", selection: $secondRemovalIndex) {
                                ForEach(-1...transitions.count - 1, id: \.self) { index in
                                    getTransitionText(index: index)
                                }
                            }
                            .pickerStyle(.wheel)
                            .frame(maxHeight: 120)
                            .disabled(!isAsymmetric)
                        }
                    }
                    .opacity(isAsymmetric ? 1.0 : 0.3)
                    
                    Divider()
                    
                    ValueSlider(title: "Duration", minValue: minDuration, maxValue: maxDuration, value: $duration)
                }
                
                Button("Show") {
                    toggleTopView()
                }
                .buttonStyle(.borderedProminent)
            }
            .padding(24)
            
            if (isViewShown) {
                if (isAsymmetric) {
                    TopView(onDismiss: toggleTopView).transition(.asymmetric(insertion: buildTransition(isInsertion: true), removal: buildTransition(isInsertion: false)))
                }
                else {
                    TopView(onDismiss: toggleTopView).transition(buildTransition(isInsertion: true))
                }
            }
        }
        .navigationTitle("Transitions")
        .navigationBarTitleDisplayMode(.inline)
    }
    
    private func getTransitionText(index: Int) -> Text {
        if (index == -1) {
            return Text("None").font(.system(size: 16))
        }
        else {
            let tr = transitions[index]
            return Text("\(tr.title)").font(.system(size: 16))
        }
    }
    
    private func buildTransition(isInsertion: Bool) -> AnyTransition {
        let firstIndex = isInsertion ? firstInsertionIndex : firstRemovalIndex
        let secondIndex = isInsertion ? secondInsertionIndex : secondRemovalIndex
        
        if (firstIndex > -1 && secondIndex > -1) {
            return transitions[firstIndex].value.combined(with: transitions[secondIndex].value)
        }
        if (firstIndex > -1) {
            return transitions[firstIndex].value
        }
        if (secondIndex > -1) {
            return transitions[secondIndex].value
        }
        return AnyTransition.slide
    }
    
    private func toggleTopView() {
        let anim = animations[animationIndex].value
        let speed = 1 / duration;
        withAnimation(anim.speed(speed)) {
            isViewShown.toggle()
        }
    }
}

struct TransitionItem {
    var title: String
    var value: AnyTransition
}

struct AnimationItem {
    var title: String
    var value: Animation
}

struct TopView: View {
    var onDismiss: () -> Void
    
    var body: some View {
        ZStack {
            Rectangle().fill(Color(UIColor(hexCode: "#E1006C")))
            VStack {
                Spacer()
                Text("Hi").font(.system(size: 24, weight: .bold)).foregroundColor(.white)
                Spacer()
                Button("Hide") {
                    onDismiss()
                }
                .buttonStyle(.borderedProminent)
            }
            .padding(24)
        }
    }
}

struct TransitionsView_Previews: PreviewProvider {
    static var previews: some View {
        TransitionsView()
    }
}
